package com.kyivmohyla.kma2.client.presenter.manager;

import com.google.gwt.event.dom.client.*;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.media.client.Audio;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.user.datepicker.client.DateBox;
import com.google.gwt.view.client.ListDataProvider;
import com.kyivmohyla.kma2.client.LoginService;
import com.kyivmohyla.kma2.client.UserService;
import com.kyivmohyla.kma2.client.events.manager.ManagerCloseOrderEvent;
import com.kyivmohyla.kma2.client.gin.Injector;
import com.kyivmohyla.kma2.client.presenter.Presenter;
import com.kyivmohyla.kma2.client.presenter.refbook.EquipmentReferenceBookPresenter;
import com.kyivmohyla.kma2.client.presenter.refbook.ServiceReferenceBookPresenter;
import com.kyivmohyla.kma2.client.utils.Dialog;
import com.kyivmohyla.kma2.client.view.common.EquipmentCellTableWidget;
import com.kyivmohyla.kma2.client.view.common.OrderHistoryWidget;
import com.kyivmohyla.kma2.client.view.common.ServiceCellTableWidget;
import com.kyivmohyla.kma2.shared.model.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class ManagerEditOrderPresenter implements Presenter {

    private final static String timeFormatString = "HH:mm";
    private final static String dateFormatString = "dd.MM.yyyy";
    private final static DateTimeFormat timeFormat = DateTimeFormat.getFormat(timeFormatString);
    private final static DateTimeFormat dateFormat = DateTimeFormat.getFormat(dateFormatString);
    private final Display display;
    private final Injector injector = Injector.INSTANCE;
    private boolean changesWereMade;
    private UIOrder existingOrder;
    private int selectedEngineerId;
    private List<UIStaff> engineers;
    private List<UIService> servicesOnOrder;
    private List<UIService> servicesOnOrderToShow;
    private List<UIService> servicesOnOrderToSave;
    private List<UIService> servicesOnOrderToDelete;
    private List<UIEquipment> equipmentOnServices;
    private List<UIEquipment> equipmentOnOrder;
    private List<UIEquipment> equipmentOnOrderToShow;
    private List<UIEquipment> equipmentOnOrderToSave;
    private List<UIEquipment> equipmentOnOrderToDelete;

    public ManagerEditOrderPresenter(UIOrder uiOrder) {
        this.display = injector.getManagerEditOrderWindowView();
        this.display.getPlannedDate().setFireNullValues(true);
        bind();

        this.existingOrder = uiOrder;
        this.selectedEngineerId = uiOrder.getEngineerId();
        this.display.getState().setText(uiOrder.getStateName());
        this.display.getPlannedDate().setFormat(new DateBox.DefaultFormat(dateFormat));
        this.display.getPlannedDate().getTextBox().setText(dateFormat.format(uiOrder.getDesStartDate()));
        selectTimeInListBox(uiOrder.getDesStartDate(), display.getDesStartTime());
        selectTimeInListBox(uiOrder.getDesEndDate(), display.getDesEndTime());

        selectTimeInListBox(uiOrder.getEndDate() == null ? uiOrder.getDesEndDate() : uiOrder.getEndDate(), display.getEndTime());
        selectTimeInListBox(uiOrder.getStartDate() == null ? uiOrder.getDesStartDate() : uiOrder.getStartDate(), display.getStartTime());

        this.display.getCommentary().setText(uiOrder.getCommentary());
        this.display.getCustomerName().setText(uiOrder.getCustomerName());
        UserService.App.getInstance().getCustomerById(uiOrder.getCustomerId(), new AsyncCallback<UICustomer>() {
            @Override
            public void onFailure(Throwable caught) {
                Dialog.getInstance().createDialogBoxWithMessage("Error", caught.getMessage());
            }

            @Override
            public void onSuccess(UICustomer result) {
                display.getCustomerPhone().setText(result.getPhone());
                display.getCustomerAddress().setText(result.getAddress());
                display.getCustomerEmail().setText(result.getEmail());
            }
        });
        UserService.App.getInstance().getHistoryByOrderId(uiOrder.getOrderId(), new AsyncCallback<List<UIHistory>>() {
            @Override
            public void onFailure(Throwable throwable) {
                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
            }

            @Override
            public void onSuccess(List<UIHistory> uiHistories) {
                ListDataProvider<UIHistory> dataProvider = new ListDataProvider<UIHistory>(uiHistories);
                dataProvider.addDataDisplay(display.getOrderHistoryCellTable().getOrderHistoryCellTable());
            }
        });
        this.display.getEngineerList().addItem("");
        if (this.selectedEngineerId == 0) {
            this.display.getEngineerList().setSelectedIndex(0);
        }
        UserService.App.getInstance().getAllEngineers(new AsyncCallback<List<UIStaff>>() {
            @Override
            public void onFailure(Throwable caught) {
                Dialog.getInstance().createDialogBoxWithMessage("Error", caught.getMessage());
            }

            @Override
            public void onSuccess(List<UIStaff> result) {
                engineers = result;
                for (UIStaff uiStaff : result) {
                    display.getEngineerList().addItem(uiStaff.getFirstName() + " " + uiStaff.getLastName());
                    if (selectedEngineerId == uiStaff.getStaffId()) {
                        display.getEngineerList().setSelectedIndex(display.getEngineerList().getItemCount() - 1);
                    }
                }
            }
        });
        UserService.App.getInstance().getServiceByOrderId(existingOrder.getOrderId(), new AsyncCallback<List<UIService>>() {
            @Override
            public void onFailure(Throwable throwable) {
                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
            }

            @Override
            public void onSuccess(List<UIService> result) {
                servicesOnOrder = new ArrayList<UIService>(result);
                servicesOnOrderToShow = new ArrayList<UIService>(result);
                ListDataProvider<UIService> dataProvider = new ListDataProvider<UIService>(servicesOnOrderToShow);
                dataProvider.addDataDisplay(display.getServiceCellTable().getServiceCellTable());
                UserService.App.getInstance().getEquipmentByServicesList(servicesOnOrderToShow, new AsyncCallback<List<UIEquipment>>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(List<UIEquipment> uiEquipments) {
                        equipmentOnServices = new ArrayList<UIEquipment>(uiEquipments);
                        final List<UIEquipment> equipmentToShow = new ArrayList<UIEquipment>(uiEquipments);
                        UserService.App.getInstance().getEquipmentByOrderId(existingOrder.getOrderId(), new AsyncCallback<List<UIEquipment>>() {
                            @Override
                            public void onFailure(Throwable throwable) {
                                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                            }

                            @Override
                            public void onSuccess(List<UIEquipment> uiEquipments) {
                                equipmentOnOrder = new ArrayList<UIEquipment>(uiEquipments);
                                equipmentOnOrderToShow = new ArrayList<UIEquipment>(uiEquipments);
                                equipmentOnOrderToDelete = new ArrayList<UIEquipment>(equipmentOnOrder);
                                equipmentOnOrderToDelete.retainAll(equipmentOnServices);
                                equipmentOnOrderToShow.removeAll(equipmentOnOrderToDelete);
                                equipmentToShow.addAll(equipmentOnOrderToShow);
                                ListDataProvider<UIEquipment> dataProvider = new ListDataProvider<UIEquipment>(equipmentToShow);
                                dataProvider.addDataDisplay(display.getEquipmentCellTable().getEquipmentCellTable());
                            }
                        });
                    }
                });
            }
        });
        changesWereMade = false;
    }

    private void fillTimeListBoxes() {
        boolean thirtyIsPut = false;
        for (int i = 8; i < 21; ) {
            display.getDesStartTime().addItem(((i < 10) ? "0" + i : i) + ":" + (thirtyIsPut ? "30" : "00"));
            display.getDesEndTime().addItem(((i < 10) ? "0" + i : i) + ":" + (thirtyIsPut ? "30" : "00"));
            display.getStartTime().addItem(((i < 10) ? "0" + i : i) + ":" + (thirtyIsPut ? "30" : "00"));
            display.getEndTime().addItem(((i < 10) ? "0" + i : i) + ":" + (thirtyIsPut ? "30" : "00"));
            if (thirtyIsPut) i++;
            thirtyIsPut = !thirtyIsPut;
        }
        display.getDesEndTime().removeItem(0);
        display.getDesEndTime().addItem("21:00");
        display.getEndTime().removeItem(0);
        display.getEndTime().addItem("21:00");
    }

    private void selectTimeInListBox(Date time, ListBox listBox) {
        //todo maybe change those deprecated methods
        int hours = time.getHours();
        int minutes = time.getMinutes();
        String parsedTime = "" + (hours < 10 ? "0" + hours : hours) + ":" + (minutes < 10 ? "0" + minutes : minutes);
        for (int i = 0; i < listBox.getItemCount(); i++)
            if (listBox.getValue(i).equals(parsedTime)) {
                listBox.setItemSelected(i, true);
                break;
            }
    }

    private String getSelectedValue(ListBox listBox) {
        return listBox.getValue(listBox.getSelectedIndex());
    }

    private Date createDateFromString(String date, String time) {
        String[] dateArray = date.split("\\.");
        String[] timeArray = time.split(":");
        return new Date(Integer.parseInt(dateArray[2]) - 1900,
                Integer.parseInt(dateArray[1]) - 1,
                Integer.parseInt(dateArray[0]),
                Integer.parseInt(timeArray[0]),
                Integer.parseInt(timeArray[1]), 0);
    }

    /*
    returns  0 if ok
    returns  1 if endTime is earlier than startTime
    returns -1 if user stepped out (desStart-desEnd) interval
    */
    private int timeValidation() {
        if (!timeFormat.parse(getSelectedValue(display.getStartTime())).before(timeFormat.parse(getSelectedValue(display.getEndTime()))))
            return 1;
        if ((timeFormat.parse(getSelectedValue(display.getDesStartTime())).getTime() > timeFormat.parse(getSelectedValue(display.getStartTime())).getTime()) ||
                timeFormat.parse(getSelectedValue(display.getDesEndTime())).getTime() < timeFormat.parse(getSelectedValue(display.getEndTime())).getTime())
            return -1;
        return 0;
    }

    private void doValidateTime(ListBox listWhereChangeOccurred, ListBox secondListBox) {
        changesWereMade = true;
        String interval = "" + getSelectedValue(display.getDesStartTime()) + " - " + getSelectedValue(display.getDesEndTime());
        display.getStartTimeInfoLabel().setText("");
        if (timeValidation() == 1) {
            secondListBox.setSelectedIndex(listWhereChangeOccurred.getSelectedIndex());
        }
        if (timeValidation() == -1) {
            display.getStartTimeInfoLabel().setText("You can not step out of (" + interval + ") interval!");
            ((Label) display.getStartTimeInfoLabel()).setStyleName("kma-InputIsInvalid");
        }
        if (timeValidation() == 0) {
            display.getStartTimeInfoLabel().setText(" OK");
            ((Label) display.getStartTimeInfoLabel()).setStyleName("kma-InputIsValid");
        }
    }

    private void bindFieldValidationHandlers() {
        this.display.getStartTime().addChangeHandler(new ChangeHandler() {
            @Override
            public void onChange(ChangeEvent event) {
                doValidateTime(display.getStartTime(), display.getEndTime());
            }
        });
        this.display.getEndTime().addChangeHandler(new ChangeHandler() {
            @Override
            public void onChange(ChangeEvent event) {
                doValidateTime(display.getEndTime(), display.getStartTime());
            }
        });
    }

    private void bind() {
        this.display.getSaveOrderButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                if (timeValidation() == 0) {
                    doSaveOrder(false);
                } else {
                    Dialog.getInstance().createDialogBoxWithMessage("Message", "Please check time");
                }
            }
        });
        this.display.getCancelButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                if (!changesWereMade) {
                    injector.getEventBus().fireEvent(new ManagerCloseOrderEvent(existingOrder.getDesStartDate()));
                } else {
                    Audio openSound = Audio.createIfSupported();
                    final DialogBox dialogBox = new DialogBox();
                    dialogBox.addStyleName("gwt-DialogBox");
                    dialogBox.setText("Confirmation");
                    HTML message = new HTML("<center>Save changes</center>");
                    VerticalPanel dialogContents = new VerticalPanel();
                    dialogContents.addStyleName("dialogContents");
                    dialogContents.setSpacing(4);
                    dialogBox.setWidget(dialogContents);
                    Button yes = new Button("Yes", new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                            if (timeValidation() == 0) {
                                doSaveOrder(true);
                            } else {
                                Dialog.getInstance().createDialogBoxWithMessage("Message", "Please Check Time");
                                dialogBox.hide();

                            }
                        }
                    });
                    Button no = new Button("No", new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                            injector.getEventBus().fireEvent(new ManagerCloseOrderEvent(existingOrder.getDesStartDate()));
                        }
                    });
                    Button cancel = new Button("Cancel", new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                            dialogBox.hide();
                        }
                    });
                    HorizontalPanel buttons = new HorizontalPanel();
                    buttons.add(yes);
                    buttons.add(no);
                    buttons.add(cancel);
                    dialogContents.add(message);
                    dialogContents.add(buttons);
                    dialogContents.setStyleName("dialogContents");
                    dialogContents.setCellHorizontalAlignment(message, HasHorizontalAlignment.ALIGN_CENTER);
                    dialogContents.setCellVerticalAlignment(message, HasVerticalAlignment.ALIGN_MIDDLE);
                    dialogContents.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
                    dialogContents.setCellVerticalAlignment(buttons, HasVerticalAlignment.ALIGN_BOTTOM);
                    dialogBox.setWidget(dialogContents);
                    dialogBox.setAnimationEnabled(true);
                    dialogBox.center();
                    openSound.setSrc("sounds/Windows Notify System Generic.wav");
                    openSound.play();
                    dialogBox.show();
                }
            }
        });
        this.display.getRejectToOperatorButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                doRejectOrder();
            }
        });
        this.display.getManageServicesButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {

                final DialogBox dialogBox = new DialogBox();
                dialogBox.addStyleName("gwt-DialogBox");
                dialogBox.setText("Service Reference Book");
                VerticalPanel dialogContents = new VerticalPanel();
                dialogContents.addStyleName("dialogContents");
                dialogContents.setSpacing(4);
                dialogBox.setWidget(dialogContents);
                final ServiceReferenceBookPresenter serviceReferenceBookPresenter;
                if (servicesOnOrderToShow == null || servicesOnOrderToShow.isEmpty()) {
                    serviceReferenceBookPresenter = new ServiceReferenceBookPresenter();
                } else {
                    serviceReferenceBookPresenter = new ServiceReferenceBookPresenter(servicesOnOrderToShow);
                }
                dialogContents.add(serviceReferenceBookPresenter.getDisplay().asWidget());
                serviceReferenceBookPresenter.getDisplay().getAddButton().addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent clickEvent) {
                        changesWereMade = true;
                        dialogBox.hide();
                        if (!servicesOnOrder.isEmpty()) {
                            servicesOnOrderToDelete = new ArrayList<UIService>(servicesOnOrder);
                            servicesOnOrderToDelete.removeAll(serviceReferenceBookPresenter.getServicesOnOrder());
                            servicesOnOrderToSave = new ArrayList<UIService>(serviceReferenceBookPresenter.getServicesOnOrder());
                            servicesOnOrderToSave.removeAll(servicesOnOrder);
                        } else {
                            servicesOnOrderToSave = new ArrayList<UIService>(serviceReferenceBookPresenter.getServicesOnOrder());
                        }
                        servicesOnOrderToShow = new ArrayList<UIService>(serviceReferenceBookPresenter.getServicesOnOrder());
                        ListDataProvider<UIService> dataProvider = new ListDataProvider<UIService>(servicesOnOrderToShow);
                        dataProvider.addDataDisplay(display.getServiceCellTable().getServiceCellTable());
                        UserService.App.getInstance().getEquipmentByServicesList(servicesOnOrderToShow, new AsyncCallback<List<UIEquipment>>() {
                            @Override
                            public void onFailure(Throwable throwable) {
                                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                            }

                            @Override
                            public void onSuccess(List<UIEquipment> uiEquipments) {
                                equipmentOnServices = new ArrayList<UIEquipment>(uiEquipments);
                                final List<UIEquipment> equipmentToShow = new ArrayList<UIEquipment>(uiEquipments);
                                UserService.App.getInstance().getEquipmentByOrderId(existingOrder.getOrderId(), new AsyncCallback<List<UIEquipment>>() {
                                    @Override
                                    public void onFailure(Throwable throwable) {
                                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                                    }

                                    @Override
                                    public void onSuccess(List<UIEquipment> uiEquipments) {
                                        equipmentOnOrder = new ArrayList<UIEquipment>(uiEquipments);
                                        equipmentOnOrderToShow = new ArrayList<UIEquipment>(uiEquipments);
                                        equipmentOnOrderToDelete = new ArrayList<UIEquipment>(equipmentOnOrder);
                                        equipmentOnOrderToDelete.retainAll(equipmentOnServices);
                                        equipmentOnOrderToShow.removeAll(equipmentOnOrderToDelete);
                                        equipmentToShow.addAll(equipmentOnOrderToShow);
                                        ListDataProvider<UIEquipment> dataProvider = new ListDataProvider<UIEquipment>(equipmentToShow);
                                        dataProvider.addDataDisplay(display.getEquipmentCellTable().getEquipmentCellTable());
                                    }
                                });
                            }
                        });
                    }
                });
                serviceReferenceBookPresenter.getDisplay().getCancelButton().addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent clickEvent) {
                        dialogBox.hide();
                    }
                });
                dialogBox.setGlassEnabled(true);
                dialogBox.setAnimationEnabled(true);
                dialogBox.center();
                dialogBox.show();
            }
        });
        this.display.getManageEquipmentButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                final DialogBox dialogBox = new DialogBox();
                dialogBox.addStyleName("gwt-DialogBox");
                dialogBox.setText("Equipment Reference Book");
                VerticalPanel dialogContents = new VerticalPanel();
                dialogContents.addStyleName("dialogContents");
                dialogContents.setSpacing(4);
                dialogBox.setWidget(dialogContents);
                final EquipmentReferenceBookPresenter equipmentReferenceBookPresenter;
                if (equipmentOnServices.isEmpty() && equipmentOnOrderToShow.isEmpty()) {
                    equipmentReferenceBookPresenter = new EquipmentReferenceBookPresenter();
                } else {
                    equipmentReferenceBookPresenter = new EquipmentReferenceBookPresenter(equipmentOnServices, equipmentOnOrderToShow);
                }
                dialogContents.add(equipmentReferenceBookPresenter.getDisplay().asWidget());
                equipmentReferenceBookPresenter.getDisplay().getAddButton().addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent clickEvent) {
                        changesWereMade = true;
                        dialogBox.hide();
                        if (equipmentOnOrder != null) {
                            equipmentOnOrderToDelete = new ArrayList<UIEquipment>(equipmentOnOrder);
                            equipmentOnOrderToDelete.removeAll(equipmentReferenceBookPresenter.getEquipmentOnOrder());
                            equipmentOnOrderToSave = new ArrayList<UIEquipment>(equipmentReferenceBookPresenter.getEquipmentOnOrder());
                            equipmentOnOrderToSave.removeAll(equipmentOnOrder);
                            equipmentOnOrderToSave.removeAll(equipmentOnServices);
                        } else {
                            equipmentOnOrderToSave = new ArrayList<UIEquipment>(equipmentReferenceBookPresenter.getEquipmentOnOrder());
                            equipmentOnOrderToSave.removeAll(equipmentOnServices);
                        }
                        equipmentOnOrderToShow = new ArrayList<UIEquipment>(equipmentReferenceBookPresenter.getEquipmentOnOrder());
                        List<UIEquipment> equipmentToShow = new ArrayList<UIEquipment>(equipmentOnServices);
                        equipmentToShow.addAll(equipmentOnOrderToShow);
                        ListDataProvider<UIEquipment> dataProvider = new ListDataProvider<UIEquipment>(equipmentToShow);
                        dataProvider.addDataDisplay(display.getEquipmentCellTable().getEquipmentCellTable());
                    }
                });
                equipmentReferenceBookPresenter.getDisplay().getCancelButton().addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent clickEvent) {
                        dialogBox.hide();
                    }
                });
                dialogBox.setGlassEnabled(true);
                dialogBox.setAnimationEnabled(true);
                dialogBox.center();
                dialogBox.show();
            }
        });
        this.display.getAccessToEngineerButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                doAccessOrder();
            }
        });
        this.display.getEngineerList().addChangeHandler(new ChangeHandler() {
            @Override
            public void onChange(ChangeEvent event) {
                changesWereMade = true;
                for (UIStaff engineer : engineers) {
                    if ((engineer.getFirstName() + " " + engineer.getLastName()).contentEquals(display.getEngineerList().getValue(display.getEngineerList().getSelectedIndex()))) {
                        selectedEngineerId = engineer.getStaffId();
                        break;
                    } else {
                        selectedEngineerId = 0;
                    }
                }
            }
        });
        bindFieldValidationHandlers();
        fillTimeListBoxes();
    }

    private void doRejectOrder() {
        if (!this.display.getMyCommentary().getText().equals("")) {
            this.existingOrder.setStateId(4);
            this.existingOrder.setCommentary(this.display.getCommentary().getText());
            UserService.App.getInstance().updateOrder(this.existingOrder, new AsyncCallback<Void>() {
                @Override
                public void onFailure(Throwable throwable) {
                    Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                }

                @Override
                public void onSuccess(Void result) {
                    Dialog.getInstance().createDialogBoxWithMessage("Success", "Order's state was changed.");
                    injector.getEventBus().fireEvent(new ManagerCloseOrderEvent(existingOrder.getDesStartDate()));
                }
            });
            final UIHistory history = new UIHistory();
            history.setChangeDate(new Date());
            history.setNewState(4);
            history.setOrderId(this.existingOrder.getOrderId());
            history.setCommentary(this.display.getMyCommentary().getText());
            LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                @Override
                public void onFailure(Throwable throwable) {
                    Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                }

                @Override
                public void onSuccess(UIStaff staff) {
                    history.setStaffId(staff.getStaffId());
                    UserService.App.getInstance().addHistory(history, new AsyncCallback<Void>() {
                        @Override
                        public void onFailure(Throwable throwable) {
                            Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                        }

                        @Override
                        public void onSuccess(Void aVoid) {
                        }
                    });
                }
            });
        } else {
            Dialog.getInstance().createDialogBoxWithMessage("Important", "Before rejecting the order You have to write a message in \"Add Commentary\" section");
        }
    }

    private void doAccessOrder() {
        if (!changesWereMade) {
            boolean access = true;
            if (this.display.getEngineerList().getSelectedIndex() == 0 || this.existingOrder.getEngineerId() == 0) {
                access = false;
                Dialog.getInstance().createDialogBoxWithMessage("Important", "Before accessing the order You have to choose an engineer and hit \"Save\" button");
            }
            if (this.existingOrder.getStateId() == 5) {
                access = false;
                Dialog.getInstance().createDialogBoxWithMessage("Message", "This order was rejected, check and save it.");
            }
            if (access) {
                List<UIOrder> orderList = new ArrayList<UIOrder>();
                orderList.add(existingOrder);
                UserService.App.getInstance().validateOrderSchedule(orderList, new AsyncCallback<Map<UIOrder, Boolean>>() {
                    @Override
                    public void onFailure(Throwable caught) {
                        Dialog.getInstance().createDialogBoxWithMessage("Message", "Something went wrong, here's original error message </br>" + caught.getMessage());
                    }

                    @Override
                    public void onSuccess(Map<UIOrder, Boolean> result) {

                        if (result.get(existingOrder)) {
                            //it means that order can be Accessed
                            existingOrder.setStateId(3);
                            UserService.App.getInstance().updateOrder(existingOrder, new AsyncCallback<Void>() {
                                @Override
                                public void onFailure(Throwable caught) {
                                    Dialog.getInstance().createDialogBoxWithMessage("Message", "Something went wrong, here's original error message </br>" + caught.getMessage());
                                }

                                @Override
                                public void onSuccess(Void result) {
                                    Dialog.getInstance().createDialogBoxWithMessage("Success", "Order was accessed to " + existingOrder.getEngineerName() + " successfully");
                                    final UIHistory history = new UIHistory();
                                    history.setChangeDate(new Date());
                                    history.setNewState(3);
                                    history.setOrderId(existingOrder.getOrderId());
                                    history.setCommentary(display.getMyCommentary().getText());
                                    LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                                        @Override
                                        public void onFailure(Throwable throwable) {
                                            Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                                        }

                                        @Override
                                        public void onSuccess(UIStaff staff) {
                                            history.setStaffId(staff.getStaffId());
                                            UserService.App.getInstance().addHistory(history, new AsyncCallback<Void>() {
                                                @Override
                                                public void onFailure(Throwable throwable) {
                                                    Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                                                }

                                                @Override
                                                public void onSuccess(Void aVoid) {
                                                    injector.getEventBus().fireEvent(new ManagerCloseOrderEvent(existingOrder.getDesStartDate()));
                                                }
                                            });
                                        }
                                    });
                                }
                            });
                        } else {
                            Dialog.getInstance().createDialogBoxWithMessage("Message", "Order can not be accessed because engineer is busy for this schedule");
                        }
                    }
                });
            }
        } else {
            Dialog.getInstance().createDialogBoxWithMessage("Message", (this.existingOrder.getStateId() == 5) ? "This order was rejected, check and save it." : "You've probably made some change. Please hit \"Save\" button just to be sure</br>");
        }
    }

    private void doSaveOrder(final boolean userWantsToCloseWindow) {
        final UIOrder uiOrder = new UIOrder();
        uiOrder.setOrderId(this.existingOrder.getOrderId());
        uiOrder.setCreateDate(this.existingOrder.getCreateDate());
        uiOrder.setDesStartDate(this.existingOrder.getDesStartDate());
        uiOrder.setDesEndDate(this.existingOrder.getDesEndDate());
        uiOrder.setStartDate(createDateFromString(display.getPlannedDate().getTextBox().getText(), getSelectedValue(display.getStartTime())));
        uiOrder.setEndDate(createDateFromString(display.getPlannedDate().getTextBox().getText(), getSelectedValue(display.getEndTime())));
        uiOrder.setStateId(2);
        uiOrder.setCustomerId(existingOrder.getCustomerId());
        uiOrder.setEngineerId(this.selectedEngineerId);
        uiOrder.setCommentary(this.display.getCommentary().getText());

        UserService.App.getInstance().updateOrder(uiOrder, new AsyncCallback<Void>() {
            @Override
            public void onFailure(Throwable caught) {
                Dialog.getInstance().createDialogBoxWithMessage("Error", caught.getMessage());
            }

            @Override
            public void onSuccess(Void result) {
                existingOrder = uiOrder;
                display.getState().setText("In Progress");
                final List<UIOrderServEquip> orderServEquipsToSave = new ArrayList<UIOrderServEquip>();
                final List<UIOrderServEquip> orderServEquipsToDelete = new ArrayList<UIOrderServEquip>();
                if (servicesOnOrderToSave != null) {
                    for (UIService service : servicesOnOrderToSave) {
                        orderServEquipsToSave.add(new UIOrderServEquip(existingOrder.getOrderId(), service.getServiceId()));
                    }
                    servicesOnOrderToSave.clear();
                }
                if (equipmentOnOrderToSave != null) {
                    for (UIEquipment equipment : equipmentOnOrderToSave) {
                        orderServEquipsToSave.add(new UIOrderServEquip(existingOrder.getOrderId(), equipment.getEquipmentId()));
                    }
                    equipmentOnOrderToSave.clear();
                }
                if (servicesOnOrderToDelete != null) {
                    for (UIService service : servicesOnOrderToDelete) {
                        orderServEquipsToDelete.add(new UIOrderServEquip(existingOrder.getOrderId(), service.getServiceId()));
                    }
                    servicesOnOrderToDelete.clear();
                }
                if (equipmentOnOrderToDelete != null) {
                    for (UIEquipment equipment : equipmentOnOrderToDelete) {
                        orderServEquipsToDelete.add(new UIOrderServEquip(existingOrder.getOrderId(), equipment.getEquipmentId()));
                    }
                    equipmentOnOrderToDelete.clear();
                }
                UserService.App.getInstance().deleteOrderServEquipList(orderServEquipsToDelete, new AsyncCallback<Void>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(Void aVoid) {
                        UserService.App.getInstance().addOrderServEquipList(orderServEquipsToSave, new AsyncCallback<Void>() {
                            @Override
                            public void onFailure(Throwable throwable) {
                                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                            }

                            @Override
                            public void onSuccess(Void aVoid) {
                                servicesOnOrder = new ArrayList<UIService>(servicesOnOrderToShow);
                                Dialog.getInstance().createDialogBoxWithMessage("Success", "Order was updated.");
                                changesWereMade = false;
                                if (userWantsToCloseWindow) {
                                    injector.getEventBus().fireEvent(new ManagerCloseOrderEvent(existingOrder.getDesStartDate()));
                                }
                            }
                        });
                    }
                });
            }
        });
    }

    @Override
    public void go(HasWidgets container) {
        container.clear();
        container.add(display.asWidget());
    }

    public interface Display {

        HasText getState();

        HasText getCustomerName();

        HasText getCustomerPhone();

        HasText getCustomerAddress();

        HasText getCustomerEmail();

        DateBox getPlannedDate();

        ListBox getDesStartTime();

        ListBox getDesEndTime();

        ListBox getStartTime();

        ListBox getEndTime();

        HasText getStartTimeInfoLabel();

        HasText getCommentary();

        HasText getMyCommentary();

        ListBox getEngineerList();

        HasClickHandlers getSaveOrderButton();

        HasClickHandlers getCancelButton();

        HasClickHandlers getRejectToOperatorButton();

        HasClickHandlers getAccessToEngineerButton();

        ServiceCellTableWidget getServiceCellTable();

        EquipmentCellTableWidget getEquipmentCellTable();

        OrderHistoryWidget getOrderHistoryCellTable();

        Widget asWidget();

        HasClickHandlers getManageServicesButton();

        HasClickHandlers getManageEquipmentButton();
    }
}
